#include "gb28181_catalog.h"
#include "../gb28181_service.h"
#include "../gb28181_utils.h"
#include "utils_log.h"
#include <sstream>

namespace El {
namespace GB28181 {

std::string GB28181Catalog::CreateDeviceInfoXml(const SipServerConfig &config, const std::string &sn)
{
    EL_DEBUG("Creating DeviceInfo XML for device {}, SN: {}", config.device_id, sn);
    int channel_count = config.channel_count;
    if (!config.channels.empty()) {
        channel_count = static_cast<int>(config.channels.size());
    }
    std::stringstream xml;
    xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        << "<Response>\n"
        << "<CmdType>DeviceInfo</CmdType>\n"
        << "<SN>" << sn << "</SN>\n"
        << "<DeviceID>" << config.device_id << "</DeviceID>\n"
        << "<DeviceName>GB28181 Device</DeviceName>\n"
        << "<Manufacturer>IPC</Manufacturer>\n"
        << "<Model>GB28181-Device</Model>\n"
        << "<Firmware>1.0.0</Firmware>\n"
        << "<MaxCamera>" << channel_count << "</MaxCamera>\n"
        << "<MaxAlarm>0</MaxAlarm>\n"
        << "</Response>\n";

    return xml.str();
}

std::string GB28181Catalog::CreateCatalogXml(const SipServerConfig &config, const std::string &sn)
{
    const bool has_explicit_channels = !config.channel_configs.empty();
    const bool has_channel_list = !config.channels.empty();
    const int list_size = has_explicit_channels
                              ? static_cast<int>(config.channel_configs.size())
                              : (has_channel_list ? static_cast<int>(config.channels.size()) : config.channel_count);

    EL_DEBUG("Creating Catalog XML for device {}, SN: {}, channels: {}", config.device_id, sn, list_size);
    std::stringstream xml;
    xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        << "<Response>\n"
        << "<CmdType>Catalog</CmdType>\n"
        << "<SN>" << sn << "</SN>\n"
        << "<DeviceID>" << config.device_id << "</DeviceID>\n"
        << "<SumNum>" << list_size << "</SumNum>\n"
        << "<DeviceList Num=\"" << list_size << "\">\n";

    for (int i = 0; i < list_size; ++i) {
        std::string channel_id;
        std::string channel_name;

        if (has_explicit_channels) {
            channel_id = config.channel_configs[i].id;
            channel_name = config.channel_configs[i].name;
        } else if (has_channel_list && i < static_cast<int>(config.channels.size())) {
            channel_id = config.channels[i];
        }

        if (channel_id.empty()) {
            channel_id = GenerateChannelId(config.device_id, i);
        }

        if (channel_name.empty()) {
            channel_name = "Channel " + std::to_string(i + 1);
        }

        xml << "<Item>\n"
            << "<DeviceID>" << channel_id << "</DeviceID>\n"
            << "<Name>" << channel_name << "</Name>\n"
            << "<Manufacturer>IPC</Manufacturer>\n"
            << "<Model>Camera</Model>\n"
            << "<Owner>IPC</Owner>\n"
            << "<CivilCode>" << config.civil_code << "</CivilCode>\n"
            << "<Block>Block</Block>\n"
            << "<Address>Address</Address>\n"
            << "<Parental>0</Parental>\n"
            << "<SafetyWay>0</SafetyWay>\n"
            << "<RegisterWay>1</RegisterWay>\n"
            << "<Status>ON</Status>\n"
            << "</Item>\n";
    }

    xml << "</DeviceList>\n"
        << "</Response>\n";

    return xml.str();
}

std::string GB28181Catalog::CreateChannelListXml(const std::vector<ChannelInfo> &channels)
{
    std::stringstream xml;

    for (const auto &channel : channels) {
        xml << "<Item>\n"
            << "<DeviceID>" << channel.device_id << "</DeviceID>\n"
            << "<Name>" << channel.name << "</Name>\n"
            << "<Manufacturer>" << channel.manufacturer << "</Manufacturer>\n"
            << "<Model>" << channel.model << "</Model>\n"
            << "<Owner>" << channel.owner << "</Owner>\n"
            << "<CivilCode>" << channel.civil_code << "</CivilCode>\n"
            << "<Address>" << channel.address << "</Address>\n"
            << "<Parental>" << channel.parental << "</Parental>\n"
            << "<SafetyWay>" << channel.safety_way << "</SafetyWay>\n"
            << "<RegisterWay>" << channel.register_way << "</RegisterWay>\n"
            << "<Status>" << channel.status << "</Status>\n"
            << "</Item>\n";
    }

    return xml.str();
}

bool GB28181Catalog::ParseDeviceInfoQuery(const std::string &xml, std::string &sn, std::string &device_id)
{
    // Simple XML parsing for DeviceInfo query
    size_t pos = xml.find("<CmdType>DeviceInfo</CmdType>");
    if (pos == std::string::npos) {
        return false;
    }

    // Extract SN
    pos = xml.find("<SN>");
    if (pos != std::string::npos) {
        size_t end = xml.find("</SN>", pos);
        if (end != std::string::npos) {
            sn = xml.substr(pos + 4, end - pos - 4);
        }
    }

    // Extract DeviceID
    pos = xml.find("<DeviceID>");
    if (pos != std::string::npos) {
        size_t end = xml.find("</DeviceID>", pos);
        if (end != std::string::npos) {
            device_id = xml.substr(pos + 10, end - pos - 10);
        }
    }

    return !sn.empty() && !device_id.empty();
}

bool GB28181Catalog::ParseCatalogQuery(const std::string &xml, std::string &sn, std::string &device_id)
{
    // Simple XML parsing for Catalog query
    size_t pos = xml.find("<CmdType>Catalog</CmdType>");
    if (pos == std::string::npos) {
        return false;
    }

    // Extract SN
    pos = xml.find("<SN>");
    if (pos != std::string::npos) {
        size_t end = xml.find("</SN>", pos);
        if (end != std::string::npos) {
            sn = xml.substr(pos + 4, end - pos - 4);
        }
    }

    // Extract DeviceID
    pos = xml.find("<DeviceID>");
    if (pos != std::string::npos) {
        size_t end = xml.find("</DeviceID>", pos);
        if (end != std::string::npos) {
            device_id = xml.substr(pos + 10, end - pos - 10);
        }
    }

    return !sn.empty() && !device_id.empty();
}

std::string GB28181Catalog::GenerateChannelId(const std::string &device_id, int channel_index)
{
    std::string channel_id = device_id;
    if (!channel_id.empty() && channel_index >= 0 && channel_index < 10) {
        // Modify last digit for channel ID
        channel_id[channel_id.length() - 1] = '0' + channel_index + 1;
    }
    return channel_id;
}

GB28181Catalog::DeviceInfo GB28181Catalog::GetDefaultDeviceInfo(const std::string &device_id, int channel_count)
{
    DeviceInfo info;
    info.device_id = device_id;
    info.device_name = "GB28181 Device";
    info.manufacturer = "IPC";
    info.model = "GB28181-Device";
    info.firmware = "1.0.0";
    info.max_camera = channel_count;
    info.max_alarm = 0;
    return info;
}

GB28181Catalog::ChannelInfo GB28181Catalog::GetDefaultChannelInfo(const std::string &device_id,
                                                                  int channel_index,
                                                                  const std::string &civil_code)
{
    ChannelInfo info;
    info.device_id = GenerateChannelId(device_id, channel_index);
    info.name = "Channel " + std::to_string(channel_index + 1);
    info.manufacturer = "IPC";
    info.model = "Camera";
    info.owner = "IPC";
    info.civil_code = civil_code;
    info.address = "Address";
    info.parental = 0;
    info.safety_way = 0;
    info.register_way = 1;
    info.status = "ON";
    return info;
}

} // namespace GB28181
} // namespace El
